#!/usr/bin/python
# -*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

u"""
gui_typedchoosers provides widgets specialized for Datum objects.

See make_chooser, make_selector
"""

__all__ = [
  u'CHOOSERS',
  u'GuiChooser',
  u'GuiBoolChooser',
  u'GuiCoordinateChooser',
  u'GuiFloatChooser',
  u'GuiIntChooser',
  u'GuiPathChooser',
  u'GuiUnfoldChooser',
  u'GuiTypedChooser',
  u'GuiUnicodeChooser',
  u'GuiPredefUnicodeChooser',
  u'GuiRadioUnicodeChooser',
  u'GuiRadioBoolChooser',
  u'make_chooser',
  ]

from Qt4 import QtGui
from Qt4.QtCore import SIGNAL
from Qt4.compat import *

from _pylot.qtgui.styles.policy import *
from _pylot.qtgui.default.impl_typedchooser import GuiTypedChooser
from _pylot.qtgui.widgets.gui_typedselectors import *
from _pylot.qtgui.custom import DEFAULT_CUSTOM
from _pylot.qtgui.tools import get_icon

from pyLot.core import (datum_name, unicode2, Path, DirPath, FilePath,
                        Coordinate, Datum)

class GuiChooser (GuiTypedChooser):
  def __init__(self, datum, selector,
               custom=DEFAULT_CUSTOM):
    GuiTypedChooser.__init__(self, datum)
    self.custom = custom
    self._data_widget = selector
    self._base_layout.addWidget(self._data_widget)
    self._translate()
    self._createConnexions()

    enabled = self.custom.getOption('enabled', self, datum, None)
    if enabled is not None :
      self.setEnabled(enabled)

  def onDatumValueListChanged(self, datum, value):
    pass

  def onDatumDefaultValueChanged(self, datum, old, new):
    pass

  def onDatumValueChanged(self, datum, old, new):
    self._data_widget.setValue(new)


class GuiIntChooser (GuiChooser):

  nature = int

  def __init__(self, datum, datarange=(0, 1000000),
               custom=DEFAULT_CUSTOM):
    selector = GuiIntSelector(datum, datarange, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

class GuiBoolChooser (GuiChooser):

  nature = bool

  def __init__(self, datum,
               custom=DEFAULT_CUSTOM):
    selector = GuiBoolSelector(datum, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

class GuiUnfoldChooser (GuiChooser):

  nature = bool

  def __init__(self, datum,
               custom=DEFAULT_CUSTOM):
    selector = GuiUnfoldSelector(datum, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

class GuiCoordinateChooser (GuiChooser):

  nature = Coordinate

  def __init__(self, datum,
               custom=DEFAULT_CUSTOM):
    selector = GuiCoordinateSelector(datum, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

class GuiPredefUnicodeChooser (GuiChooser):

  nature = unicode

  def __init__(self, datum,
               custom=DEFAULT_CUSTOM):
    selector = GuiPredefUnicodeSelector(datum, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

  def onDatumValueListChanged(self, datum, value):
    self._data_widget.refresh()

class GuiRadioUnicodeChooser (GuiChooser):

  nature = unicode

  def __init__(self, datum,
               custom=DEFAULT_CUSTOM):
    selector = GuiRadioUnicodeSelector(datum, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

class GuiRadioBoolChooser (GuiChooser):

  nature = bool

  def __init__(self, datum,
               custom=DEFAULT_CUSTOM):
    selector = GuiRadioBoolSelector(datum, custom=custom)
    GuiChooser.__init__(self, datum, selector, custom=custom)

class GuiUnicodeChooser (GuiTypedChooser):

  nature = unicode

  def __init__(self, datum, editable=True, check=None,
               data_class=None,
               custom=DEFAULT_CUSTOM):
    GuiTypedChooser.__init__(self, datum)
    self.custom = custom
    self._check = check

    if data_class :
      data = data_class(datum, editable, check, custom=custom)
    else :
      data = GuiUnicodeSelector(datum, editable, check, custom=custom)

    data.setEditable(editable)
    data.setSizePolicy(QSizePolicy(Minimum, Fixed))
    data.setMinimumWidth(100)
    self._base_layout.addWidget(data)
    self._data_widget = data

    try :
      self._base_layout.setStretch(0, 1)
      self._base_layout.setStretch(1, 3)
    except AttributeError : # Qt < 4.5
      pass

    self._createConnexions()

  def _getValue(self):
    return self.self._data_widget.value()

  def onDatumValueListChanged(self, datum, value):
    lst = [val for val in datum.value_list]
    self._data_widget.setValueList(lst)

  def onDatumDefaultValueChanged(self, datum, old, new):
    self._data_widget.setDefaultValue(new)

  def onDatumValueChanged(self, datum, old, new):
    self._data_widget.setValue(new)


class GuiFloatChooser (GuiUnicodeChooser):
  u"""
  A unicode string selector.
  
  ** SIGNALS **

  - SIGNAL dataChanged [value] : this signal is sent when line editing is
    finished. value is the new value
  """

  nature = float

  def __init__(self, datum, editable=True, check=None,
               custom=DEFAULT_CUSTOM):
    GuiUnicodeChooser.__init__(self, datum, editable, check, GuiFloatSelector,
                               custom=custom)

class GuiPathChooser(GuiUnicodeChooser):

  nature = Path

  def __init__(self, datum, editable=True, check=None,
               custom=DEFAULT_CUSTOM):
    self.pb_open = QtGui.QPushButton(u'Open')
    GuiUnicodeChooser.__init__(self, datum, editable, check, GuiPathSelector,
                               custom=custom)
    self._decorate()

  def _decorate(self):
    self.pb_open.setIcon(get_icon(u'optionsOpen.png'))

  def _createConnexions(self):
    GuiUnicodeChooser._createConnexions(self)
    self.pb_open.clicked.connect(self.actionOpenPath)

  def getPostWidgets(self):
    return [self.pb_open]

  def actionOpenPath(self):
    path, filters = getopenfilename()
    if path :
      self.setValue(path)

class GuiFilePathChooser(GuiPathChooser):

  nature = FilePath

  def actionOpenPath(self):
    path, filters = getopenfilename()
    if path :
      self.setValue(path)

class GuiDirPathChooser(GuiPathChooser):

  nature = DirPath

  def actionOpenPath(self):
    path = getexistingdirectory()
    if path :
      self.setValue(path)

class GuiSaveFilePathChooser(GuiPathChooser):

  nature = FilePath

  def actionOpenPath(self):
    path, filters = getsavefilename()
    if path :
      self.setValue(path)


class GuiOldPathChooser (GuiUnicodeChooser):
  u"""
  GuiPathChooser provides a file or directory selector based on a datum object.

  Example of use :
  
  >>> from Qt4.QtGui import QApplication
  >>> app = QApplication([])
  >>> from pyLot.core import Datum, FilePath
  >>> d = Datum(u'd', FilePath, u'/', u'/home', alias=u'Mon Path')
  >>> path_chooser = GuiPathChooser(d)
  >>> path_chooser.show()
  >>> ret = app.exec_()

  Once created, you can get value with 
  :meth:`~pylot.qtgui.GuiPathChooser.getValue`.
  
  If you want to update original datum (Datum passed during GuiPathChooser
  initialization) you must do it explicitly by calling 
  :meth:`~pylot.qtgui.GuiPathChooser.updateData`.

  If you want to customize widget, you should have a look to
  :meth:`~pylot.qtgui.GuiPathChooser.getPushButton` and
  :meth:`~pylot.qtgui.GuiPathChooser.getDataWidget` methods.
  
  .. seealso ::
  
    :class:`~pylot.core.Datum`, :class:`~pylot.core.Path`
    :class:`~pylot.core.FilePath` and :class:`~pylot.core.DirPath`

  """
  ButtonNo = 0
  ButtonLeft = 1
  ButtonRight = 2
  nature = Path

  def __init__(self, datum, scroll_area=False,
               style=ButtonRight, editable=True, check_exists=False,
               custom=DEFAULT_CUSTOM):
    u"""
    :param scroll_area: if True, set path chooser in a scroll area.
    """
    self._check_exists = check_exists
    self.initial_path = Path(u'.')
    GuiUnicodeChooser.__init__(self, datum, editable=editable)

    self._label_widget = QtGui.QLabel()
    self._push_button = QtGui.QPushButton(self)
    self._push_button.setSizePolicy(QSizePolicy(Fixed, Maximum))
    self._push_button.setMinimumWidth(60)
    pb_id = u'_'.join([u'QPushButton', datum.name])
    self._push_button.setObjectName(pb_id)
    self._push_button.connect(self._push_button, SIGNAL("clicked()"),
                              self.chooseDir)

    if scroll_area :
      content = QtGui.QWidget()
      self._addWidgets(content, style)

      layout = QtGui.QHBoxLayout(content)
      self._addWidgets()

      scroll_area = QtGui.QScrollArea(self)
      scroll_area.setFrameShape(QtGui.QFrame.NoFrame)
      scroll_area.setWidgetResizable(True)
      scroll_area.setSizePolicy(QSizePolicy(Maximum, Preferred))
      scroll_area.setWidget(content)
      self._base_layout.addWidget(scroll_area)
    else :
      self._addWidgets(self._base_layout, style)

    self._createConnexions()
    self._translate()
    self._decorate()

  def _addWidgets(self, layout, style):
    if style == self.ButtonLeft :
      layout.addWidget(self._push_button)
      layout.addWidget(self._label_widget)
      layout.addWidget(self._data_widget)
    elif style == self.ButtonRight :
      layout.addWidget(self._label_widget)
      layout.addWidget(self._data_widget)
      layout.addWidget(self._push_button)
      try:
        layout.setStretch(0, 1)
        layout.setStretch(1, 3)
      except AttributeError : # Qt < 4.5
        pass
    elif style == self.ButtonNo :
      layout.addWidget(self._data_widget)

  def _decorate(self):
    self._push_button.setIcon(self._icon(u'dir.png'))

  def _translate(self):
    GuiTypedChooser._translate(self)
    msg = tr_(u"If no directory in combobox agrees, click here to select" \
            u"existing directory.")
    self._push_button.setToolTip(msg)
    self._label_widget.setText(tr_(datum_name(self._datum)))

  def getPushButton(self):
    u"""
    Returns the push button widget which launches the path selector
    
    :rtype: QtGui.QPushButton
    """
    return self._push_button

  def getPostWidgets(self):
    return [self._push_button]

  def getPreWidgets(self):
    return []

  def chooseDir(self):
    u"""
    Method called when user clicks on "select path" button.
    Create and display a path selector.
    
    The type of path selector (directory or file) depends on datum's nature.
    """
    pb_id = self.sender().objectName()
    datum = self._datum
    datum_id = datum.name

    if self.initial_path :
      initial_path = self.initial_path
    else :
      initial_path = datum.value

    if issubclass(datum.nature, FilePath) :
      rep = QtGui.QFileDialog.getOpenFileName (self,
        unicode2(datum.alias), initial_path)
    else :
      rep = QtGui.QFileDialog.getExistingDirectory (self,
        unicode2(datum.alias), initial_path)

    if unicode(rep) :
      self.setValue(unicode(rep))


DEFAULT_CHOOSERS = [
  GuiBoolChooser,
  GuiIntChooser,
  GuiFloatChooser,
  GuiUnicodeChooser,
  GuiPathChooser,
  GuiDirPathChooser,
  GuiFilePathChooser,
  GuiCoordinateChooser
  ]

CHOOSERS = {}
for chooser in DEFAULT_CHOOSERS :
  CHOOSERS[chooser.nature] = chooser

def make_chooser(datum, custom=DEFAULT_CUSTOM):
  u"""
  make_chooser provide view for datum.
  Like in Model/View programming, changing model automatically update
  view.  
  """
  global DEFAULT_CHOOSERS

  from pyLot.application import APPLICATION
  pm = APPLICATION.getPluginManager()
  DEFAULT_CHOOSERS = DEFAULT_CHOOSERS + pm.get_extensions('pyLot.qtgui.choosers')
  for chooser in DEFAULT_CHOOSERS :
    CHOOSERS[chooser.nature] = chooser

  try :
    chooser_class = CHOOSERS[datum.nature]
  except KeyError :
    chooser_class = None

  chooser_class = custom.getOption(u'chooser', None, datum, chooser_class)
  if chooser_class :
    return chooser_class(datum, custom=custom)
  else :
    return None

if __name__ == '__main__' :
  import doctest
  doctest.testmod()

  from Qt4.QtGui import QApplication
  app = QApplication([])

  d1 = Datum(u'file', FilePath, u'/', u'/home', tooltip=u'Un chemin', alias=u'Mon Path')
  chooser1 = GuiPathChooser(d1)
  chooser1.show()

  d2 = Datum(u'int', int, 1, tooltip=u'Un entier', alias=u'Mon entier')
  chooser2 = GuiIntChooser(d2)
  chooser2.show()

  d3 = Datum(u'bool', bool, 1, tooltip=u'Un booléen', alias=u'Mon booléen')
  chooser3 = GuiBoolChooser(d3)
  chooser3.show()

  d4 = Datum(u'float', float, 1, tooltip=u'Un décimal', alias=u'Mon décimal')
  chooser4 = GuiFloatChooser(d4)
  chooser4.show()

  d5 = Datum(u'unicode', unicode, u'¡ Ciao !', tooltip=u'Une chaîne', alias=u'Ma chaîne')
  chooser5 = GuiUnicodeChooser(d5)
  chooser5.show()

  ret = app.exec_()
